package com.qf.drbackend.filters;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.qf.drbackend.pojos.R;
import com.qf.drbackend.utils.JwtUtils;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.SignatureException;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Map;

public class VerityTokenFilter extends BasicAuthenticationFilter {
    public VerityTokenFilter(AuthenticationManager authenticationManager) {
        super(authenticationManager);
    }


    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
        //获取请求头的token信息，完成jwt的合法性校验
        String token = request.getHeader("token");

        //兼容同步请求的登录认证需求（同步请求无法设置请求头，所以通过url后拼接请求参数方式携带）
        if (StringUtils.isBlank(token)){
            token = request.getParameter("token");
        }

        if (StringUtils.isBlank(token)){
            //为null或者长度为0
            chain.doFilter(request,response);
            return;
        }

        //不为null，并且长度不为0
        try {
            Claims claims = JwtUtils.parseBody(token);

            //用户id
            String uid = claims.getSubject();
            //放行之前，要向security上下文中存入认证对象
            /*
                参数一：当前登录用户的uid
                参数二：当前登录用户的密码（不需要）
                参数三：当前用户的权限信息（没有）
             */
            Authentication auth = new UsernamePasswordAuthenticationToken(uid,null,null);
            SecurityContextHolder.getContext().setAuthentication(auth);

            //放行
            chain.doFilter(request,response);
            return;
        }catch (ExpiredJwtException expiredJwtException){
            //jwt过期了  假设jwt2小时过期， 签发时间是12：30分 --》过期时间14：30
            //假设用户在14：29分使用应用， 用了1分钟，提示重新登录。 给一个可以复活的时间
            long expireTime = expiredJwtException.getClaims().getExpiration().getTime();
            long nowTime = System.currentTimeMillis();
            if (nowTime - expireTime > 1000*60*60){
                //过期时间太久了，重新登录
            }else{
                //过期时间不太长,认为是可以登录.并且要更新浏览器端的token
                Claims claims = expiredJwtException.getClaims();
                String uid = claims.getSubject();
                String newToken = JwtUtils.createToken(claims, uid);
                response.setHeader("refresh_token",newToken);

                Authentication auth = new UsernamePasswordAuthenticationToken(uid,null,null);
                SecurityContextHolder.getContext().setAuthentication(auth);
                //放行
                chain.doFilter(request,response);

                return;
            }


        }catch (SignatureException signatureException){
            //非法签名（jwt的内容被篡改了）
            signatureException.printStackTrace();
        }catch (Exception e){
            //未知错误
            e.printStackTrace();
        }

        //提示重新登录
        R r = R.error("NOTLOGIN");
        String json = new ObjectMapper().writeValueAsString(r);
        response.getWriter().write(json);
    }
}
